import pandas
import requests
from bs4 import BeautifulSoup
from datetime import datetime
from tqdm import tqdm
from vfeeds import DataFeed

eastMoneyAdjustFlags = {
    "bfq": "0",
    "qfq": "1",
    "hfq": "2"
}

eastMoneyIntervalMaps = {
    "1min": "1",
    "5min": "5",
    "15min": "15",
    "30min": "30",
    "H": "60",
    "D": "101",
    "W": "102",
    "M": "103"
}


def get_stock_market(stock_code):
    if stock_code.startswith(("00", "12", "13", "18", "15", "16", "18", "20", "30", "39", "115", "1318")):
        return "SZ"
    if stock_code.startswith(("5", "6", "9", "7", "110", "113", "132", "204")):
        return "SH"
    if stock_code.startswith(("4", "8")):
        return "BJ"


class ConceptBoardFeed(DataFeed):
    def get_detail(self):
        result = list()
        data_json = requests.get("http://79.push2.eastmoney.com/api/qt/clist/get", params={
            "pn": "1",
            "pz": "2000",
            "np": "1",
            "invt": "2",
            "fs": "m:90 t:3 f:!50",
            "fields": "f2,f8,f12,f14,f15,f16,f17,f18,f20,f21,f104,f105,f124,f128,f136,f140",
        }, timeout=15).json()
        for item in data_json["data"]["diff"]:
            result.append({
                "datetime": datetime.fromtimestamp(item["f124"]).strftime("%Y-%m-%d %H:%M:%S"),
                "title": item["f14"],
                "symbol": item["f12"],
                "open": item["f17"],
                "high": item["f15"],
                "low": item["f16"],
                "close": item["f2"],
                "pre_close": item["f18"],
                "turnover_rate": item["f8"],
                "total_market_value": item["f20"],
                "float_market_value": item["f21"],
                "up_number": item["f104"],
                "down_number": item["f105"],
                "leader_title": item["f128"],
                "leader_change_rate": item["f136"],
                "leader_symbol": item["f140"] + "." + get_stock_market(item["f140"])
            })
        return result

    def get_history(self, symbol, interval, start, end, adjust="qfq"):
        result = list()
        data_json = requests.get("http://91.push2his.eastmoney.com/api/qt/stock/kline/get", params={
            "secid": f"90.{symbol}",
            "fields1": "f1,f2,f3,f4,f5,f6",
            "fields2": "f51,f52,f53,f54,f55,f56,f57",
            "klt": eastMoneyIntervalMaps[interval],
            "fqt": eastMoneyAdjustFlags[adjust],
            "beg": start.strftime("%Y%m%d"),
            "end": end.strftime("%Y%m%d")
        }, timeout=15).json()
        for item in data_json["data"]["klines"]:
            row_data = item.split(",")
            result.append({
                "datetime": row_data[0],
                "open": float(row_data[1]),
                "high": float(row_data[3]),
                "low": float(row_data[4]),
                "close": float(row_data[2]),
                "volume": float(row_data[5]),
                "amount": float(row_data[6]),
            })
        return result

    @staticmethod
    def get_stock_list(symbol):
        data_json = requests.get("http://29.push2.eastmoney.com/api/qt/clist/get", params={
            "pn": "1",
            "pz": "2000",
            "np": "1",
            "fs": f"b:{symbol} f:!50",
            "fields": "f12",
        }, timeout=15).json()
        return [item["f12"] + "." + get_stock_market(item["f12"]) for item in data_json["data"]["diff"]]


class IndustryBoardFeed(DataFeed):
    def get_detail(self):
        result = list()
        data_json = requests.get("http://17.push2.eastmoney.com/api/qt/clist/get", params={
            "pn": "1",
            "pz": "2000",
            "np": "1",
            "fltt": "2",
            "fs": "m:90 t:2 f:!50",
            "fields": "f2,f8,f12,f14,f15,f16,f17,f18,f20,f21,f104,f105,f124,f128,f136,f140"
        }, timeout=15).json()
        for item in data_json["data"]["diff"]:
            result.append({
                "datetime": datetime.fromtimestamp(item["f124"]).strftime("%Y-%m-%d %H:%M:%S"),
                "title": item["f14"],
                "symbol": item["f12"],
                "open": item["f17"],
                "high": item["f15"],
                "low": item["f16"],
                "close": item["f2"],
                "pre_close": item["f18"],
                "turnover_rate": item["f8"],
                "total_market_value": item["f20"],
                "float_market_value": item["f21"],
                "up_number": item["f104"],
                "down_number": item["f105"],
                "leader_title": item["f128"],
                "leader_change_rate": item["f136"],
                "leader_symbol": item["f140"] + "." + get_stock_market(item["f140"])
            })
        return result

    def get_history(self, symbol, interval, start, end, adjust="qfq"):
        result = list()
        data_json = requests.get("http://7.push2his.eastmoney.com/api/qt/stock/kline/get", params={
            "secid": f"90.{symbol}",
            "fields1": "f1,f2,f3,f4,f5,f6",
            "fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61",
            "klt": eastMoneyIntervalMaps[interval],
            "fqt": eastMoneyAdjustFlags[adjust],
            "beg": start.strftime("%Y%m%d"),
            "end": end.strftime("%Y%m%d"),
        }, timeout=15).json()
        for item in data_json["data"]["klines"]:
            row_data = item.split(",")
            result.append({
                "datetime": row_data[0],
                "open": float(row_data[1]),
                "high": float(row_data[3]),
                "low": float(row_data[4]),
                "close": float(row_data[2]),
                "volume": float(row_data[5]),
                "amount": float(row_data[6]),
            })
        return result

    @staticmethod
    def get_stock_list(symbol):
        r = requests.get("http://29.push2.eastmoney.com/api/qt/clist/get", params={
            "pn": "1",
            "pz": "2000",
            "np": "1",
            "fs": f"b:{symbol} f:!50",
            "fields": "f12"
        }, timeout=15)
        print(r.url)
        data_json = requests.get("http://29.push2.eastmoney.com/api/qt/clist/get", params={
            "pn": "1",
            "pz": "2000",
            "np": "1",
            "fs": f"b:{symbol} f:!50",
            "fields": "f12"
        }, timeout=15).json()
        return [item["f12"] + "." + get_stock_market(item["f12"]) for item in data_json["data"]["diff"]]


class IndexBoardDatafeed(object):
    @staticmethod
    def get_detail():
        result = list()
        data_json = requests.get("https://38.push2.eastmoney.com/api/qt/clist/get", params={
            "pn": 1,
            "pz": 2000,
            "np": 1,
            "fltt": 2,
            "fs": "m:1+s:3,m:0+t:5",
            "fields": "f2,f5,f6,f10,f12,f14,f15,f16,f17,f18",
        }, timeout=15).json()
        for item in data_json["data"]["diff"]:
            result.append({
                "title": item["f14"],
                "symbol": item["f12"] + "." + get_stock_market(item["f12"]),
                "open": item["f17"],
                "high": item["f15"],
                "low": item["f16"],
                "close": item["f2"],
                "volume": item["f5"],
                "amount": item["f6"],
                "pre_close": item["f18"],
                "pe": item["f10"]
            })
        return result

    @staticmethod
    def get_history(symbol, interval, start, end, adjust="qfq"):
        result = list()
        data_json = requests.get("http://push2his.eastmoney.com/api/qt/stock/kline/get", params={
            "secid": ".".join(symbol.replace("SZ", "0").replace("SH", "1").split(".")[::-1]),
            "fields1": "f1,f2,f3,f4,f5",
            "fields2": "f51,f52,f53,f54,f55,f56,f57",
            "klt": eastMoneyIntervalMaps[interval],  # 日频率
            "fqt": eastMoneyAdjustFlags[adjust],
            "beg": start.strftime("%Y%m%d"),
            "end": end.strftime("%Y%m%d")
        }, timeout=15).json()
        for item in data_json["data"]["klines"]:
            row_data = item.split(",")
            result.append({
                "datetime": row_data[0],
                "open": float(row_data[1]),
                "high": float(row_data[3]),
                "low": float(row_data[4]),
                "close": float(row_data[2]),
                "volume": float(row_data[5]),
                "amount": float(row_data[6]),
            })
        return result

    @staticmethod
    def get_stock_list(symbol):
        code, _ = symbol.split(".")
        result = list()
        respond = requests.get(
            url=f"https://vip.stock.finance.sina.com.cn/corp/go.php/vII_NewestComponent/indexid/{code}.phtml"
        )
        respond.encoding = "gb2312"
        soup = BeautifulSoup(respond.text, "lxml")
        page_num = (
            soup.find(attrs={"class": "table2"})
            .find("td")
            .find_all("a")[-1]["href"]
            .split("page=")[-1]
            .split("&")[0]
        )
        if page_num == "#":
            temp_df = pandas.read_html(respond.text, header=0, skiprows=1)[3]
        else:
            temp_df = pandas.DataFrame()
            for page in tqdm(range(1, int(page_num) + 1)):
                resp = requests.get(
                    url="https://vip.stock.finance.sina.com.cn/corp/view/vII_NewestComponent.php",
                    params={
                        "indexid": code,
                        "page": page
                    }
                )
                resp.encoding = "gb2312"
                temp_df = pandas.concat(
                    [temp_df, pandas.read_html(resp.text, header=1)[3]], ignore_index=True
                )
        temp_df = temp_df.iloc[:, :3]
        temp_df.columns = ["symbol", "-", "-"]
        for symbol in temp_df["symbol"].astype(str).str.zfill(6).tolist():
            result.append(symbol + "." + get_stock_market(symbol))
        return result


class StockFeed(DataFeed):
    def get_detail(self):
        result = list()
        data_json = requests.get("http://82.push2.eastmoney.com/api/qt/clist/get", params={
            "pn": "1",
            "pz": "50000",
            "np": "1",
            "fltt": "2",
            "fs": "m:0 t:6,m:0 t:80,m:1 t:2,m:1 t:23,m:0 t:81 s:2048",
            "fields": "f2,f5,f6,f8,f9,f10,f12,f14,f15,f16,f17,f18,f20,f21,f124",
        }, timeout=15).json()
        for item in data_json["data"]["diff"]:
            result.append({
                "datetime": datetime.fromtimestamp(item["f124"]).strftime("%Y-%m-%d %H:%M:%S"),
                "title": item["f14"],
                "symbol": item["f12"] + "." + get_stock_market(item["f12"]),
                "open": item["f17"],
                "high": item["f15"],
                "low": item["f16"],
                "close": item["f2"],
                "pre_close": item["f18"],
                "turnover_rate": item["f8"],
                "qr": item["f10"],
                "pe": item["f9"],
                "total_market_value": item["f20"],
                "float_market_value": item["f21"]
            })
        return result

    def get_history(self, symbol, interval, start, end, adjust="qfq"):
        result = list()
        data_json = requests.get("https://push2his.eastmoney.com/api/qt/stock/kline/get", params={
            "secid": ".".join(symbol.replace("SZ", "0").replace("SH", "1").split(".")[::-1]),
            "fields1": "f1,f2,f3,f4,f5",
            "fields2": "f51,f52,f53,f54,f55,f56,f57",
            "klt": eastMoneyIntervalMaps[interval],  # 日频率
            "fqt": eastMoneyAdjustFlags[adjust],
            "beg": start.strftime("%Y%m%d"),
            "end": end.strftime("%Y%m%d")
        }, timeout=15).json()
        for item in data_json["data"]["klines"]:
            row_data = item.split(",")
            result.append({
                "datetime": row_data[0],
                "open": float(row_data[1]),
                "high": float(row_data[3]),
                "low": float(row_data[4]),
                "close": float(row_data[2]),
                "volume": float(row_data[5]),
                "amount": float(row_data[6]),
            })
        return result


__all__ = [ConceptBoardFeed, IndustryBoardFeed, IndexBoardDatafeed, StockFeed]